package com.kun.companion.core.http;

import okhttp3.Interceptor;

import javax.net.ssl.SSLHandshakeException;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * HTTP客户端配置类，用于定义连接超时、读写超时、连接池参数及自定义拦截器列表
 *
 * @author gzc
 * @since 2025/3/1
 **/
public class ClientConfig {
    private long connectTimeout;
    private long readTimeout;
    private long writeTimeout;
    private PoolConfig poolConfig;
    private RetryConfig retryConfig;
    private List<Interceptor> interceptorList;

    /**
     * 全参构造方法
     *
     * @param connectTimeout  连接超时时间（秒）
     * @param readTimeout     读取超时时间（秒）
     * @param writeTimeout    写入超时时间（秒）
     * @param poolConfig      连接池配置
     * @param interceptorList 自定义拦截器列表
     */
    public ClientConfig(long connectTimeout,
                        long readTimeout,
                        long writeTimeout,
                        PoolConfig poolConfig,
                        RetryConfig retryConfig,
                        List<Interceptor> interceptorList) {
        this.connectTimeout = connectTimeout;
        this.readTimeout = readTimeout;
        this.writeTimeout = writeTimeout;
        this.poolConfig = poolConfig;
        this.retryConfig = retryConfig;
        this.interceptorList = interceptorList;
    }

    /**
     * 创建默认配置实例
     *
     * @return 默认配置：
     * - 连接超时：10秒
     * - 读写超时：15秒
     * - 连接池：最大空闲50，保活5分钟，心跳30秒
     * - 拦截器：空列表（容量1）
     */
    public static ClientConfig defaultConfig() {
        // 重试以下异常
        List<Class<? extends Exception>> retryableExceptionList = Arrays.asList(
                IOException.class,
                SocketTimeoutException.class,
                SSLHandshakeException.class
        );
        RetryConfig retryConfig = new RetryConfig(5, 1000, 1.5, new ArrayList<>(), retryableExceptionList);
        ArrayList<Interceptor> interceptorList = new ArrayList<>(1);
//        interceptorList.add(new RetryInterceptor(retryConfig));
        return new ClientConfig(
                10,
                15,
                15,
                new PoolConfig(50, 5, 30),
                retryConfig,
                interceptorList
        );
    }

    /**
     * 连接池配置类
     */
    public static class PoolConfig {
        /**
         * 最大空闲连接数
         */
        private int maxIdle;
        /**
         * 保活时间（分钟）
         */
        private long keepAlive;
        /**
         * 心跳间隔（秒）
         */
        private int pingInterval;

        public PoolConfig(int maxIdle, long keepAlive, int pingInterval) {
            this.maxIdle = maxIdle;
            this.keepAlive = keepAlive;
            this.pingInterval = pingInterval;
        }

        public int getMaxIdle() {
            return maxIdle;
        }

        public void setMaxIdle(int maxIdle) {
            this.maxIdle = maxIdle;
        }

        public long getKeepAlive() {
            return keepAlive;
        }

        public void setKeepAlive(long keepAlive) {
            this.keepAlive = keepAlive;
        }

        public int getPingInterval() {
            return pingInterval;
        }

        public void setPingInterval(int pingInterval) {
            this.pingInterval = pingInterval;
        }
    }

    /**
     * 重试配置类
     */
    public static class RetryConfig {
        /**
         * 最大尝试次数（包括首次请求）
         */
        private int maxAttempts;
        /**
         * 基础重试间隔（毫秒）
         */
        private long baseInterval;
        /**
         * 退避系数（建议>=1）
         */
        private double backoffFactor;
        /**
         * 可重试异常类型
         */
        private List<Class<? extends Exception>> retryableExceptions;

        private List<Integer> retryableStatusCodeList;

        public RetryConfig(int maxAttempts, long baseInterval,
                           double backoffFactor,
                           List<Integer> retryableStatusCodeList,
                           List<Class<? extends Exception>> retryableExceptions) {
            this.maxAttempts = maxAttempts;
            this.baseInterval = baseInterval;
            this.backoffFactor = backoffFactor;
            this.retryableStatusCodeList = retryableStatusCodeList;
            this.retryableExceptions = retryableExceptions;
        }

        public int getMaxAttempts() {
            return maxAttempts;
        }

        public void setMaxAttempts(int maxAttempts) {
            this.maxAttempts = maxAttempts;
        }

        public long getBaseInterval() {
            return baseInterval;
        }

        public void setBaseInterval(long baseInterval) {
            this.baseInterval = baseInterval;
        }

        public double getBackoffFactor() {
            return backoffFactor;
        }

        public void setBackoffFactor(double backoffFactor) {
            this.backoffFactor = backoffFactor;
        }

        public List<Class<? extends Exception>> getRetryableExceptions() {
            return retryableExceptions;
        }

        public void setRetryableExceptions(List<Class<? extends Exception>> retryableExceptions) {
            this.retryableExceptions = retryableExceptions;
        }

        public List<Integer> getRetryableStatusCodeList() {
            return retryableStatusCodeList;
        }

        public void setRetryableStatusCodeList(List<Integer> retryableStatusCodeList) {
            this.retryableStatusCodeList = retryableStatusCodeList;
        }
    }


    public long getConnectTimeout() {
        return connectTimeout;
    }

    public void setConnectTimeout(long connectTimeout) {
        this.connectTimeout = connectTimeout;
    }

    public long getReadTimeout() {
        return readTimeout;
    }

    public void setReadTimeout(long readTimeout) {
        this.readTimeout = readTimeout;
    }

    public long getWriteTimeout() {
        return writeTimeout;
    }

    public void setWriteTimeout(long writeTimeout) {
        this.writeTimeout = writeTimeout;
    }

    public PoolConfig getPoolConfig() {
        return poolConfig;
    }

    public void setPoolConfig(PoolConfig poolConfig) {
        this.poolConfig = poolConfig;
    }

    public List<Interceptor> getInterceptorList() {
        return interceptorList;
    }

    public void setInterceptorList(List<Interceptor> interceptorList) {
        this.interceptorList = interceptorList;
    }
}
